﻿/* 
   Copyright 2011 LUCA Studios LLC & John Evans

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

namespace LUCAStudios.Silverlight.Controls
{
    using System;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using DragDrop;
    using Windows;

    /// <summary>
    /// Handles window dragging, resizing...
    /// </summary>
    internal class LUCAWindowManipulator : WindowManipulatorBase
    {
        private readonly TimeSpan _dropTargetDelay = TimeSpan.FromSeconds(.3);

        public LUCAWindowManipulator(Panel rootPanel) : base(rootPanel) { }

        /// <summary>
        /// Manually begins a window drag operation using the given drag handle.
        /// This is rather advanced and would normally happen automatically via a click event on the
        /// draghandle element.  
        /// </summary>
        /// <param name="dragHandle"></param>
        /// <param name="offset">an optional offset value for the initial clickpoint position</param>
        internal void ForceWindowDragState(FrameworkElement dragHandle, Point offset)
        {
            Canvas.SetZIndex(ClickTargetLookup[dragHandle].DragElement, ZOrder++);
            CurrentCursor = Cursors.Arrow;
            CurrentTransformDelegate = TransformDrag;

            var win = (IWindow)ClickTargetLookup[dragHandle];

            win.OnDragStarted();
            OnWindowDragStart(win);

            RootPanel.Cursor = CurrentCursor;
            CurrentTransformDelegate = TransformDrag;
            CapturedElement = dragHandle;

            ClickPoint = dragHandle.GetPosition(RootPanel);
            ClickPoint = new Point(ClickPoint.X + offset.X < 0 ? 0 : ClickPoint.X + offset.X, ClickPoint.Y + offset.Y < 0 ? 0 : ClickPoint.Y + offset.Y);

            RootPanel.MouseLeftButtonUp += RootPanelMouseLeftButtonUp;
            RootPanel.MouseLeave += RootPanelMouseLeave;

            //wait for the rest of the layout to update before generating drop targets
            //HACK: this isn't very clean, but we need to be "sure" the layout has updated, and
            //there is no guarantee at this point that it hasn't updated already.
            Observable
                .Timer(_dropTargetDelay)
                .ObserveOnDispatcher() //prevent cross-thread issues
                .Subscribe(_ => GenerateDropTargets(ClickTargetLookup[dragHandle] as IDragDropSource));
        }
    }
}